/*
    wifi station example
*/
#include "led.h"
#include "station.h"
#include "string.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h" 
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "lwip/err.h"
#include "lwip/sys.h"

#define AP_WIFI_SSID       "Redmi"                      /* AP 账号 */
#define AP_WIFI_PASSWORD   "lin111983"                  /* AP 密码 */
#define ESP_MAXIMUM_RETRY   10                          /* wifi 最大重连次数 */

static EventGroupHandle_t s_wifi_event_group;           /* 定义一个 wifi 事件组，FreeRTOS 事件组在我们连接时发出信号 */
static const char *TAG = "wifi station";

#define WIFI_CONNECTED_BIT      BIT0                    /* esp32 连接 AP 标志位*/
#define WIFI_FAIL_BIT           BIT1                    /* 达到最大重试次数后连接失败标志位 */

static int s_retry_num = 0;                             /* wifi 重连次数 */

/*
    esp32 wifi event handler
 */
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
                                int32_t event_id, void *event_data)
{
    if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
    {
        esp_wifi_connect();                                             /* 连接 AP wifi */
    }
    else if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
    {
        if(s_retry_num < ESP_MAXIMUM_RETRY)
        {
            esp_wifi_connect();                                         /* 尝试重连 wifi */
            s_retry_num++;
            led_blink();
            ESP_LOGI(TAG, "retry to connect to the AP.");
        }
        else
        {
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);      /* 设置事件组 wifi 连接失败标志位 */
        }
        led_off();
        ESP_LOGI(TAG, "connect to the AP fail.");
    }
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
    {
        ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        s_retry_num = 0;
        led_on();
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);     /* 设置事件组 wifi 连接成功标志位 */
    }
}

/*
    esp32 wifi init
*/
void wifi_init_station(void)
{
    s_wifi_event_group = xEventGroupCreate();           /* 创建事件组 */

    ESP_ERROR_CHECK(esp_netif_init());                  /* esp32 网络初始化 */
    ESP_ERROR_CHECK(esp_event_loop_create_default());   /* esp32 创建默认事件循环 */
    esp_netif_create_default_wifi_sta();                /* esp32 创建默认 wifi 基站 */

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();/* wifi 默认配置 */
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));               /* esp32 wifi 初始化默认配置 */

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;

    /* esp 事件注册 */
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        &instance_got_ip));                        

    /* esp wifi config */
    wifi_config_t wifi_config = {
        .sta = {
            .ssid = AP_WIFI_SSID,                           /* AP wifi 账号 */
            .password = AP_WIFI_PASSWORD,                   /* AP wifi 密码 */
            .threshold.authmode = WIFI_AUTH_WPA2_PSK,       /* 加密模式 */
            .pmf_cfg = {
                .capable = true,
                .required = false
            },
        },
    };                

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));                  /* wifi 模式设置 */     
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));    /* wifi 配置 */                              
    ESP_ERROR_CHECK(esp_wifi_start());                                  /* wifi 启动 */

    led_blink();
    ESP_LOGI(TAG, "esp32 wifi station init finished.");

    /* 等待连接到 AP */
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
                                           WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
                                           pdFALSE,
                                           pdFALSE,
                                           portMAX_DELAY);
    /* 测试发生了哪些事件 */
    if(bits & WIFI_CONNECTED_BIT)
    {
        ESP_LOGI(TAG, "connected to AP ssid:%s, password:%s",
                            AP_WIFI_SSID, AP_WIFI_PASSWORD);
    }
    else if(bits & WIFI_FAIL_BIT)
    {
        ESP_LOGI(TAG, "Failed to connect to AP ssid:%s, password:%s",
                            AP_WIFI_SSID, AP_WIFI_PASSWORD);
    }
    else
    {
        ESP_LOGI(TAG, "UNEXPECTED EVENT");
    }

    /* 注销后将不会处理该事件 */
    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT,
                                                          IP_EVENT_STA_GOT_IP,
                                                          instance_got_ip));
    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT,
                                                          ESP_EVENT_ANY_ID,
                                                          instance_any_id));
    vEventGroupDelete(s_wifi_event_group);      /* 删除事件组 */
}

/* esp32 wifi station demo*/
void wifi_sta_mode_config_test(void)
{
    esp_err_t ret = nvs_flash_init();
    if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ESP_ERROR_CHECK(nvs_flash_init());
    }

    led_init();
    
    wifi_init_station();
}